From f09338c8ded26ecb620937b4a10e59614460a065 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Mon, 28 Jun 2021 17:48:04 +0200 Subject: [PATCH] gtkeventcontrollerscroll: Handle hold gestures Handle hold events: - GDK_TOUCHPAD_GESTURE_PHASE_BEGIN: scroll-begin is emitted. - GDK_TOUCHPAD_GESTURE_PHASE_END: A hold gesture ends only when all fingers are lifted from the touchpad without movement, so scroll-end is emitted right away. - GDK_TOUCHPAD_GESTURE_PHASE_CANCEL: A hold gesture is cancelled when some fingers are lifted/put down or movement is detected. In this case, scroll-end is emitted after a small timeout only if GDK_SCROLL wasn't detected. Part-of: --- gtk/gtkeventcontrollerscroll.c | 78 +++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/gtk/gtkeventcontrollerscroll.c b/gtk/gtkeventcontrollerscroll.c index e0acee7a2e..67dafb73ed 100644 --- a/gtk/gtkeventcontrollerscroll.c +++ b/gtk/gtkeventcontrollerscroll.c @@ -66,6 +66,7 @@ #include "gtkprivate.h" #define SCROLL_CAPTURE_THRESHOLD_MS 150 +#define HOLD_TIMEOUT_MS 50 typedef struct { @@ -84,6 +85,7 @@ struct _GtkEventControllerScroll double cur_dx; double cur_dy; + guint hold_timeout_id; guint active : 1; }; @@ -193,6 +195,7 @@ gtk_event_controller_scroll_finalize (GObject *object) GtkEventControllerScroll *scroll = GTK_EVENT_CONTROLLER_SCROLL (object); g_array_unref (scroll->scroll_history); + g_clear_handle_id (&scroll->hold_timeout_id, g_source_remove); G_OBJECT_CLASS (gtk_event_controller_scroll_parent_class)->finalize (object); } @@ -272,6 +275,70 @@ gtk_event_controller_scroll_end (GtkEventController *controller) return TRUE; } +static gboolean +gtk_event_controller_scroll_hold_timeout (gpointer user_data) +{ + GtkEventController *controller; + GtkEventControllerScroll *scroll; + + controller = user_data; + scroll = GTK_EVENT_CONTROLLER_SCROLL (controller); + + gtk_event_controller_scroll_end (controller); + scroll->hold_timeout_id = 0; + + return G_SOURCE_REMOVE; +} + +static gboolean +gtk_event_controller_scroll_handle_hold_event (GtkEventController *controller, + GdkEvent *event) +{ + GtkEventControllerScroll *scroll = GTK_EVENT_CONTROLLER_SCROLL (controller); + gboolean handled = GDK_EVENT_PROPAGATE; + GdkTouchpadGesturePhase phase; + guint n_fingers = 0; + + if (gdk_event_get_event_type (event) != GDK_TOUCHPAD_HOLD) + return handled; + + n_fingers = gdk_touchpad_event_get_n_fingers (event); + if (n_fingers != 1 && n_fingers != 2) + return handled; + + if (scroll->hold_timeout_id != 0) + return handled; + + phase = gdk_touchpad_event_get_gesture_phase (event); + + switch (phase) + { + case GDK_TOUCHPAD_GESTURE_PHASE_BEGIN: + handled = gtk_event_controller_scroll_begin (controller); + break; + + case GDK_TOUCHPAD_GESTURE_PHASE_END: + handled = gtk_event_controller_scroll_end (controller); + break; + + case GDK_TOUCHPAD_GESTURE_PHASE_CANCEL: + if (scroll->hold_timeout_id == 0) + { + scroll->hold_timeout_id = + g_timeout_add (HOLD_TIMEOUT_MS, + gtk_event_controller_scroll_hold_timeout, + controller); + } + break; + + case GDK_TOUCHPAD_GESTURE_PHASE_UPDATE: + default: + break; + } + + return handled; +} + static gboolean gtk_event_controller_scroll_handle_event (GtkEventController *controller, GdkEvent *event, @@ -282,14 +349,22 @@ gtk_event_controller_scroll_handle_event (GtkEventController *controller, GdkScrollDirection direction = GDK_SCROLL_SMOOTH; double dx = 0, dy = 0; gboolean handled = GDK_EVENT_PROPAGATE; + GdkEventType event_type; + + event_type = gdk_event_get_event_type (event); - if (gdk_event_get_event_type (event) != GDK_SCROLL) + if (event_type == GDK_TOUCHPAD_HOLD) + return gtk_event_controller_scroll_handle_hold_event (controller, event); + + if (event_type != GDK_SCROLL) return FALSE; if ((scroll->flags & (GTK_EVENT_CONTROLLER_SCROLL_VERTICAL | GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL)) == 0) return FALSE; + g_clear_handle_id (&scroll->hold_timeout_id, g_source_remove); + /* FIXME: Handle device changes */ direction = gdk_scroll_event_get_direction (event); if (direction == GDK_SCROLL_SMOOTH) @@ -484,6 +559,7 @@ gtk_event_controller_scroll_init (GtkEventControllerScroll *scroll) { scroll->scroll_history = g_array_new (FALSE, FALSE, sizeof (ScrollHistoryElem)); + scroll->hold_timeout_id = 0; } /** -- 2.30.2